import { v4 as uuidv4 } from 'uuid'
import { isArrayOfArrays } from '../utils/index.js'
import imgMarker from '../static/image/2004.png'
import { coordinateUtils } from '../utils/index.js'

export default {
  addPolyline,
  addPolygon,
  addMarkers,
  addPoints,
  addBoxes,
  addLabels,
  addModel,
  removeEntityById,
  removeAllEntities
}
/**
 * 添加线段
 * @param { Array } coordinates 坐标 必传 格式: [[lng, lat], [lng, lat], ...]
 * @param { Number } width 线条宽度 default:2
 * @param { Boolean } isDash 是否为虚线 default:false
 * @param { Boolean } clampToGround 线条是否贴地 default:true
 * @param { Object } dashOption 虚线设置
 * @param { Cesium.HeightReference } heightReference 默认从地面算起的相对高度
 * @returns { Object } 返回添加的线段实体
 */
function addPolyline (config) {
  const {
    name,
    description,
    coordinates = [],
    width = 2,
    color = Cesium.Color.RED, // 设置线条颜色
    opacity = 1,
    dashOption = {},
    clampToGround = true, // 线条是否贴地
    heightReference = Cesium.HeightReference.NONE
  } = config || {}

  if (!coordinates || !coordinates.length) {
    throw Error('addPolyline: coordinates is required')
  }

  const id = config.id || uuidv4()
  const positions = _transToCartesian3(coordinates)
  const {
    dashLength = 5.0,// 虚线中实线的长度
    // dashPattern = [5, 10], // 实线长度5，间隙长度10
    gapColor = Cesium.Color.BLACK.withAlpha(0.0) // 间隙颜色
  } = dashOption
  const material = Object.keys(dashOption).length ? new Cesium.PolylineDashMaterialProperty({
    color,
    dashLength,
    gapColor
  }) : Cesium.Color.fromCssColorString(color).withAlpha(opacity)

  const polyline = this.viewer.entities.add({
    id,
    name,
    description,
    polyline: {
      positions,
      width,
      material,
      heightReference
    },
    clampToGround
  })
  return polyline
}
/**
 * 添加多边形
 * @param {String | Number} id 实体id 
 * @param { String } name 设置实体名称
 * @param { String } description 设置描述信息 
 * @param { String } color 设置颜色 默认 #ffffff
 * @param { Number } opacity 设置透明度 默认 1
 * @param { Array } coordinates 多边形坐标 必传 格式: [lng, lat, lng, lat, ...]
 * @param { Array } holes 多边形孔洞坐标 格式:[[lng, lat,lng, lat,lng, lat], ...]
 * @param { Boolean } outline 是否显示轮廓 默认 true
 * @param { String } outlineColor 设置多边形轮廓颜色 默认 Cesium.Color.BLACK
 * @param { Number } outlineWidth 设置多边形轮廓宽度 默认 2
 * @param { Number } extrudedHeight 定义了多边形边缘（壁）的高度 默认 0
 * @param { Number } height 多边形底部到地球表面的高度 默认 0.1
 * @param { Boolean } perPositionHeight 是否每个位置都使用高度 默认 true
 * @returns { Object} 返回添加的多边形实体
 */
function addPolygon (config) {
  const {
    name, // 设置实体名称
    description,// 设置描述信息
    coordinates = [],
    holeCoords = [], // 多边形孔洞坐标
    color = '#ffffff', // 设置多边形颜色
    opacity = 1,
    outline = true, // 是否显示轮廓
    outlineColor = Cesium.Color.BLACK, // 设置多边形轮廓颜色,
    outlineWidth = 2,// 设置多边形轮廓宽度
    extrudedHeight = 0,// 定义了多边形边缘（壁）的高度
    height = 0.1, //多边形底部到地球表面的高度
    perPositionHeight = true, // 是否每个位置都使用高度
    // heightReference = Cesium.HeightReference.NONE,
  } = config || {}
  const id = config.id || uuidv4()
  if (!coordinates || !coordinates.length) {
    throw Error('addPolygon: coordinates is required')
  }
  const positions = _transToCartesian3(coordinates)
  const holes = holeCoords.length ? holeCoords.map((v) => {
    return { positions: _transToCartesian3(v) }
  }) : undefined
  const polygon = this.viewer.entities.add({
    id,
    name,
    description,
    polygon: {
      hierarchy: {
        positions,
        holes
      },// 设置多边形的坐标
      material: Cesium.Color.fromCssColorString(color).withAlpha(opacity),// 设置多边形颜色
      outline,
      outlineColor,
      outlineWidth,
      extrudedHeight,
      height,
      perPositionHeight,
      // heightReference
    },
  })
  return polygon
}
/**
 * 添加标记
 * @param {Array} markers 标记数组 coordinate 必传
 * @returns {Array} 返回添加的标记实体数组
 */
function addMarkers (markers = []) {
  const markerEntity = markers.map(item => {
    const {
      id = uuidv4(), // 实体id
      name, // 实体名称
      scale = 1, // 缩放比例
      coordinate = [], // 坐标 必传 格式: [lng, lat]
      description, // 描述信息
      img = imgMarker, // 图片路径 默认使用内置图片
      offset = [0, 0], // 偏移量
      color = Cesium.Color.WHITE.withAlpha(1), // 颜色与透明度
      horizontalOrigin = Cesium.HorizontalOrigin.CENTER, // 水平对齐方式
      verticalOrigin = Cesium.VerticalOrigin.BOTTOM,// 垂直对齐方式
      clampToGround = true, // 是否贴地
      depthTest = false, // 禁用深度测试
      heightReference = Cesium.HeightReference.CLAMP_TO_GROUND,// 使用 CLAMP_TO_GROUND 模式
      disableDepthTestDistance = Number.POSITIVE_INFINITY // 禁用深度测试
    } = item || {}
    if (!coordinate || !coordinate.length) {
      throw Error('addMarkers: coordinate is required')
    }
    const [lng, lat] = coordinate
    const position = coordinateUtils.lnglatToCartesian3(lng, lat)
    const marker = this.viewer.entities.add({
      id,
      name,
      position,
      description,
      depthTest,
      disableDepthTestDistance,
      billboard: {
        image: img,
        scale,
        color,
        pixelOffset: new Cesium.Cartesian2(...offset), // 像素偏移量
        horizontalOrigin,
        verticalOrigin,
        // clampToGround,
        heightReference
      }
    })
    return marker
  })
  return markerEntity
}
/**
 * 添加点位
 * @param {Array} points 点位数组 coordinate 必传
 * @returns {Array} 返回添加的点位实体数组
 * @example
 * this.viewer.addPoint([
 * {
 *   id: 'point1',
 *   name: '点位1',
 *   coordinate: [116.397128, 39.916527],
 *   description: '这是一个点位',
 *   pixelSize: 10, 
 *   outlineWidth: 5, 
 *   properties: {},
 *   color: Cesium.Color.fromCssColorString('#66FF46').withAlpha(1),
 *   outlineColor: Cesium.Color.fromCssColorString('#66FF46').withAlpha(0.3), 
 *   show: true
 * }
 * ])
 */
function addPoints (points = []) {
  const pointEntity = points.map((item) => {
    const {
      id = uuidv4(), // 实体id
      name, // 实体名称
      coordinate = [], // 坐标 必传 格式: [lng, lat]
      description, // 描述信息
      pixelSize = 10, // 点的像素大小
      outlineWidth = 5, // 点的轮廓宽度
      properties = {},
      show = true, // 是否显示
      color = Cesium.Color.fromCssColorString('#66FF46').withAlpha(1), // 颜色与透明度
      outlineColor = Cesium.Color.fromCssColorString('#66FF46').withAlpha(0.3), // 点的轮廓颜色
      disableDepthTestDistance = Number.POSITIVE_INFINITY, // 解决缩小地图层级点位显示不全的问题
    } = item || {}
    if (!coordinate || !coordinate.length) {
      throw Error('addPoints: coordinate is required')
    }
    const [lng, lat] = coordinate
    const position = coordinateUtils.lnglatToCartesian3(lng, lat)
    const point = this.viewer.entities.add({
      id,
      name,
      description,
      position,
      point: {
        pixelSize,
        color,
        outlineColor,
        outlineWidth,
        show,
        disableDepthTestDistance,
      },
      properties
    })
    return point
  })
  return pointEntity

}
/**
 *  添加立方体
 * @param {Array} boxs 立方体数组 coordinate 必传
 * @returns {Array} 返回添加的立方体实体数组
 * @example 
 * this.viewer.addBoxs([
 * {
 *   id: 'box1',
 *   name: '立方体1',
 *   coordinate: [116.397128, 39.916527，200],
 *   description: '这是一个立方体',
 *   size：[3, 2, 8],
 *   properties: {},
 *   color: Cesium.Color.fromCssColorString('#66FF46').withAlpha(1),
 *   outlineColor: Cesium.Color.fromCssColorString('#66FF46').withAlpha(0.3), 
 * }
 * ])
 */
function addBoxes (boxs = []) {
  const boxEntity = boxs.map((item) => {
    const {
      id = uuidv4(), // 实体id
      name, // 实体名称
      coordinate = [], // 坐标 必传 格式: [lng, lat]
      description, // 描述信息
      properties = {},
      size = [1, 1, 1], // 尺寸：指定框的长度 宽度 高度
      color = Cesium.Color.fromCssColorString('#66FF46').withAlpha(1),  // 用于填充框的材料
      outlineColor = Cesium.Color.WHITE, //指定轮廓的颜色
      outline = false, // 是否对框进行概述
      heightReference, // 高度参考模式
    } = item || {}
    if (!coordinate || !coordinate.length) {
      throw Error('addBoxs: coordinate is required')
    }
    const [lng, lat, height = 0] = coordinate
    const [x, y, z] = size
    const position = coordinateUtils.lnglatToCartesian3(lng, lat, height)
    const dimensions = new Cesium.Cartesian3(Number(x), Number(y), Number(z))

    const box = this.viewer.entities.add({
      id,
      name,
      position,
      description,
      box: {
        dimensions,
        outline, // 是否对框进行概述
        material: color,
        outlineColor,
        heightReference
      },
      properties,
    })
    return box
  })
  return boxEntity
}
/**
 * 添加标签
 * @param {Array} labels 标签数组 coordinate 必传
 * @returns {Array} 返回添加的标签实体数组
 */
function addLabels (labels = []) {
  const labelEntity = labels.map(item => {
    const {
      id = uuidv4(),
      name, // 实体名称
      description, // 描述信息
      coordinate = [], // 坐标 必传 格式: [lng, lat]
      font = "14px sans-serif",
      fillColor = Cesium.Color.WHITE,// 字体颜色
      backgroundColor = Cesium.Color.BLACK.withAlpha(0.8),// 背景颜色
      showBackground = true,
      horizontalOrigin = Cesium.HorizontalOrigin.CENTER, // 水平位置
      verticalOrigin = Cesium.VerticalOrigin.BOTTOM,// 垂直位置 用于指定相对于对象的原点的垂直位置
      pOffset = [], // 指定像素偏移量
      eOffset = [], // 指定眼偏移量
      scale = 1.0,
      padding = [0, 0],
      show = true, // 是否显示
      heightReference,
      distanceDisplayCondition = new Cesium.DistanceDisplayCondition(0, 4.5e8), // 指定在距离摄像机的距离上显示该标签
      disableDepthTestDistance = Number.POSITIVE_INFINITY, // 指定
    } = item || {}

    if (!coordinate || !coordinate.length) {
      throw Error('addLabels: coordinate is required')
    }
    const [lng = 0, lat = 0, height = 0] = coordinate
    const [px = 0, py = 0] = pOffset
    const [ex = 0, ey = 0, ez = 0] = eOffset
    const position = coordinateUtils.lnglatToCartesian3(lng, lat, height)
    const pixelOffset = new Cesium.Cartesian2(Number(px), Number(py))
    const eyeOffset = new Cesium.Cartesian3(Number(ex), Number(ey), Number(ez))
    const backgroundPadding = new Cesium.Cartesian2(Number(padding[0]), Number(padding[1]))

    const label = this.viewer.entities.add({
      id,
      name,
      position,
      description,
      label: {
        show,
        text: name,
        font,
        fillColor,
        showBackground,
        backgroundColor,
        horizontalOrigin,
        verticalOrigin,
        pixelOffset,
        eyeOffset,
        scale,
        distanceDisplayCondition,
        disableDepthTestDistance,
        backgroundPadding,
        heightReference
      }
    })
    return label
  })
  return labelEntity
}
/**
 *添加模型
 * @param {String | Number} id 实体id 
 * @param { String } name 设置实体名称
 * @param { String } description 设置描述信息 
 * @param { Number } heading 航向
 * @param { Number } pitch 俯仰角
 * @param { Number } roll 翻滚角
 * @param { Array } coordinate 坐标 必传 格式: [lng, lat, lng, lat, ...]
 * @param { String } uri glTF资产的URI
 * @param { Number } maximumScale 模型的最大比例尺大小
 * @param { Number } minimumPixelSize 指定模型的最小最小像素大小
 * @param { Number } scale 缩放比例 默认 1
 * @param { Boolean } show 是否显示
 * @param { Cesium.Color  } color 设置颜色 默认 #ffffff
 * @param { Number } colorBlendAmount 指定 colorBlendMode 为 MIX 时的颜色强度
 * @param { Cesium.Color } silhouetteColor 指定轮廓的 Color
 * @param { Cesium.ColorBlendMode } colorBlendMode 指定颜色如何与模型融合
 * @param { Number } silhouetteSize 轮廓的大小
 * @returns {Object} 模型实体
 */
function addModel (config = {}) {
  const {
    id = uuidv4(),
    name,
    coordinate = [],
    heading = Cesium.Math.toRadians(0), //航向
    pitch = 0, //俯仰角
    roll = 0, // 翻滚角
    uri, // glTF资产的URI的字符串
    minimumPixelSize = 120,//指定模型的最小最小像素大小
    scale = 1,
    show = true,
    maximumScale,// 模型的最大比例尺大小
    color,
    colorBlendAmount = 0.5,// 指定 colorBlendMode 为 MIX 时的颜色强度
    colorBlendMode = Cesium.ColorBlendMode.HIGHLIGHT, // 指定颜色如何与模型融合
    silhouetteColor = Cesium.Color.BLUE, // 指定轮廓的 Color
    silhouetteSize = 2 // 轮廓的大小
  } = config || {}

  const [lng, lat, alt = 0] = coordinate
  // 创建一个模型位置
  const position = coordinateUtils.lnglatToCartesian3(lng, lat, alt)
  const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll)
  // 根据参考系计算四元数，其中参考系具有根据航向-俯仰-横滚角计算的轴以提供的原点为中心
  const orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr)

  const entity = this.viewer.entities.add({
    id,
    name,
    position,
    orientation,
    model: {
      uri,
      scale,
      show,
      minimumPixelSize,
      maximumScale,
      color,
      colorBlendMode,
      colorBlendAmount,
      silhouetteColor,
      silhouetteSize
    }
  })
  //跟踪模型
  this.viewer.trackedEntity = entity
  return entity
}
/**
 * 根据id删除实体
 * @param {*} entityId 实体id
 */
function removeEntityById (entityId) {
  this.viewer.entities.removeById(entityId)
}
/**
 * 删除所有的实体
 */
function removeAllEntities () {
  this.viewer.entities.removeAll()
}

// 获取转化后的 Cartesian3 坐标
function _transToCartesian3 (coordinates) {
  if (!coordinates || !coordinates.length) {
    return []
  }
  return isArrayOfArrays(coordinates) ? coordinates.map(v => {
    const [lng, lat] = v || []
    return Cesium.Cartesian3.fromDegrees(lng, lat)
  }) : Cesium.Cartesian3.fromDegreesArray(coordinates)
}